package com.tf_cut.backend.payment.service.impl;

import com.bill99.asap.exception.CryptoException;
import com.bill99.asap.service.ICryptoService;
import com.bill99.asap.service.impl.CryptoServiceFactory;
import com.bill99.schema.asap.commons.Mpf;
import com.bill99.schema.asap.data.SealedData;
import com.bill99.schema.asap.data.UnsealedData;
import com.tf_cut.backend.agent.vo.AgentCashOrderVo;
import com.tf_cut.backend.mapper.AgentCashMapper;
import com.tf_cut.backend.mapper.GrantDetailMapper;
import com.tf_cut.backend.payment.paydto.Pay2bankSearchRequest;
import com.tf_cut.backend.payment.paydto.Pay2bankSearchRequestParam;
import com.tf_cut.backend.payment.paydto.Pay2bankSearchResponse;
import com.tf_cut.backend.payment.paydto.Pay2bankSearchResult;
import com.tf_cut.backend.payment.service.PaymentQueryService;
import com.tf_cut.backend.platform.vo.GrantDetailVo;
import com.tf_cut.backend.util.CCSUtil_Query;
import com.tf_cut.backend.util.ConfigSettingUtil;
import com.tf_cut.backend.util.PKIUtil;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;

@Service
@Transactional
public class PaymentQueryServiceImpl implements PaymentQueryService {
    private Logger logger = LogManager.getLogger(PaymentQueryService.class);
    @Resource
    private ConfigSettingUtil configUtil;

    @Autowired
    private GrantDetailMapper grantDetailMapper;

    @Autowired
    private AgentCashMapper agentCashMapper;
    @Override
    public int queryPaymentStatusByOrderId(String orderId){
        String isPayment = configUtil.getConfigValue("payment","is_payment");    //支付开关

        //支付接口已关闭
        if("off".equals(isPayment)){
            return 9;
        }

        logger.info("发放详单支付结果查询：" + orderId + "请求中：");
        GrantDetailVo detail = grantDetailMapper.queryGrantDetailById(orderId);
        int status = queryDetail(detail);
        logger.info("发放详单支付结果查询：" + orderId + "请求完成.");

        return status;
    }

    @Override
    public int queryPaymentStatusByGrantId(String orderId){
        String isPayment = configUtil.getConfigValue("payment","is_payment");    //支付开关

        //支付接口已关闭
        if("off".equals(isPayment)){
            return 9;
        }

        logger.info("发放订单支付结果查询：" + orderId + "请求中：");
        GrantDetailVo vo = new GrantDetailVo();
        vo.setOrderId(orderId);
        List<GrantDetailVo> list = grantDetailMapper.queryGrantDetailList(vo);

        for(GrantDetailVo detail : list){
            queryDetail(detail);
        }

        logger.info("发放详单支付结果查询：" + orderId + "请求完成.");

        return 0;
    }

    @Override
    public int queryDetail(GrantDetailVo detail){
        String version = configUtil.getConfigValue("payment","version");        //接口版本
        String membercode = configUtil.getConfigValue("payment","merchant_id"); //商户号
        String fetureCode = configUtil.getConfigValue("payment","feture_code"); //策略编码
        String encoding = configUtil.getConfigValue("payment","encoding");      //字符编码

        if(!"P".equals(detail.getPaymentStatus())){
            //如果支付结果已经有了最终状态或者是线下支付，不发往第三方支付查询
            return 0;
        }


        //构建一个订单对象
        String reqXml = genQueryDetail(detail, encoding, fetureCode, membercode, version);
        //发送请求
        try {
            String respXml = sendQuery(reqXml, encoding);

            logger.info("第三方支付结果查询返回密文:" + respXml);
            Pay2bankSearchResponse response = CCSUtil_Query.converyToJavaBean(respXml, Pay2bankSearchResponse.class);
            SealedData sealedData = new SealedData();
            sealedData.setOriginalData(response.getSearchResponseBody().getSealDataType().getOriginalData()==null?null:PKIUtil.utf8String2ByteWithBase64(response.getSearchResponseBody().getSealDataType().getOriginalData()));
            sealedData.setSignedData(response.getSearchResponseBody().getSealDataType().getSignedData()==null?null:PKIUtil.utf8String2ByteWithBase64(response.getSearchResponseBody().getSealDataType().getSignedData()));
            sealedData.setEncryptedData(response.getSearchResponseBody().getSealDataType().getEncryptedData()==null?null:PKIUtil.utf8String2ByteWithBase64(response.getSearchResponseBody().getSealDataType().getEncryptedData()));
            sealedData.setDigitalEnvelope(response.getSearchResponseBody().getSealDataType().getDigitalEnvelope()==null?null:PKIUtil.utf8String2ByteWithBase64(response.getSearchResponseBody().getSealDataType().getDigitalEnvelope()));
            Mpf mpf = genMpf(fetureCode , membercode);
            UnsealedData unsealedData = null;
            try {
                ICryptoService service = CryptoServiceFactory.createCryptoService();
                unsealedData = service.unseal(mpf, sealedData);
            } catch (CryptoException e) {
                logger.error("解密失败:" + e);
            }
            byte[] decryptedData = unsealedData.getDecryptedData();
            String rtnString = "";
            if (null != decryptedData) {
                rtnString = PKIUtil.byte2UTF8String(decryptedData);
            } else {
                rtnString = PKIUtil.byte2UTF8String(sealedData.getOriginalData());
            }
            logger.info("第三方支付结果查询解密后明文：" + rtnString);

            Pay2bankSearchResult respObj = CCSUtil_Query.converyToJavaBean(rtnString, Pay2bankSearchResult.class);

            if(respObj.getResultList() != null){
                if(detail.getId().equals(respObj.getResultList().get(0).getOrderId())){
                    //第三方支付出款3种状态：101 处理中  111 成功  112 失败
                    String status = respObj.getResultList().get(0).getStatus();
                    //错误描述
                    String msg = respObj.getResultList().get(0).getErrorMsg();
                    //错误码
                    String errorCode = respObj.getResultList().get(0).getErrorCode();

                    //只有状态为处理中的才修改(防止手动置修改状态之后再次改变)
                    if(detail.getPaymentStatus().equals("P")) {
                        if (status.equals("111")) {
                            detail.setPaymentStatus("S");
                            detail.setPaymentMsg(msg);
                            grantDetailMapper.updateGrantDetailByPayment(detail);
                        } else if (status.equals("112")) {
                            detail.setPaymentStatus("F");
                            detail.setPaymentMsg(msg);
                            grantDetailMapper.updateGrantDetailByPayment(detail);
                        }
                    }
                    return 0;
                }
            }else{
                //只有状态为处理中的才修改(防止手动置修改状态之后再次改变)
                if(detail.getPaymentStatus().equals("P")) {
                    detail.setPaymentStatus("F");
                    detail.setPaymentMsg(response.getSearchResponseBody().getErrorCode() + ":" + response.getSearchResponseBody().getErrorMsg());
                    grantDetailMapper.updateGrantDetailByPayment(detail);
                }
                return 0;
            }

            return 1;
        } catch (Exception e) {
            logger.error("请求超时：", e);
            return -1;
        }
    }

    @Override
    public int queryCash(AgentCashOrderVo cash){
        String version = configUtil.getConfigValue("payment","version");        //接口版本
        String membercode = configUtil.getConfigValue("payment","merchant_id"); //商户号
        String fetureCode = configUtil.getConfigValue("payment","feture_code"); //策略编码
        String encoding = configUtil.getConfigValue("payment","encoding");      //字符编码

        if(!"P".equals(cash.getPaymentStatus())){
            //如果支付结果已经有了最终状态或者是线下支付，不发往第三方支付查询
            return 0;
        }


        //构建一个订单对象
        String reqXml = genQueryCash(cash, encoding, fetureCode, membercode, version);
        //发送请求
        try {
            String respXml = sendQuery(reqXml, encoding);
            //接收响应、解密
            logger.info("第三方支付结果查询返回密文:" + respXml);
            Pay2bankSearchResponse response = CCSUtil_Query.converyToJavaBean(respXml, Pay2bankSearchResponse.class);
            SealedData sealedData = new SealedData();
            sealedData.setOriginalData(response.getSearchResponseBody().getSealDataType().getOriginalData()==null?null:PKIUtil.utf8String2ByteWithBase64(response.getSearchResponseBody().getSealDataType().getOriginalData()));
            sealedData.setSignedData(response.getSearchResponseBody().getSealDataType().getSignedData()==null?null:PKIUtil.utf8String2ByteWithBase64(response.getSearchResponseBody().getSealDataType().getSignedData()));
            sealedData.setEncryptedData(response.getSearchResponseBody().getSealDataType().getEncryptedData()==null?null:PKIUtil.utf8String2ByteWithBase64(response.getSearchResponseBody().getSealDataType().getEncryptedData()));
            sealedData.setDigitalEnvelope(response.getSearchResponseBody().getSealDataType().getDigitalEnvelope()==null?null:PKIUtil.utf8String2ByteWithBase64(response.getSearchResponseBody().getSealDataType().getDigitalEnvelope()));
            Mpf mpf = genMpf(fetureCode , membercode);
            UnsealedData unsealedData = null;
            ICryptoService service = CryptoServiceFactory.createCryptoService();
            unsealedData = service.unseal(mpf, sealedData);
            byte[] decryptedData = unsealedData.getDecryptedData();
            String rtnString = "";
            if (null != decryptedData) {
                rtnString = PKIUtil.byte2UTF8String(decryptedData);
            } else {
                rtnString = PKIUtil.byte2UTF8String(sealedData.getOriginalData());
            }
            logger.info("第三方支付结果查询解密后明文：" + rtnString);

            Pay2bankSearchResult respObj = CCSUtil_Query.converyToJavaBean(rtnString, Pay2bankSearchResult.class);

            if(respObj.getResultList() != null) {
                if (cash.getOrderId().equals(respObj.getResultList().get(0).getOrderId())) {
                    //第三方支付出款3种状态：101 处理中  111 成功  112 失败
                    String status = respObj.getResultList().get(0).getStatus();
                    //错误描述
                    String msg = respObj.getResultList().get(0).getErrorMsg();
                    //错误码
                    String errorCode = respObj.getResultList().get(0).getErrorCode();

                    //只有状态为处理中的才修改(防止手动置修改状态之后再次改变)
                    if(cash.getPaymentStatus().equals("P")) {
                        if (status.equals("111")) {
                            cash.setPaymentStatus("S");
                            cash.setPaymentMsg(msg);
                            agentCashMapper.updateAgentCashOrderByPayment(cash.getPaymentStatus(), cash.getPaymentMsg(), cash.getOrderId());
                        } else if (status.equals("112")) {
                            cash.setPaymentStatus("F");
                            cash.setPaymentMsg(msg);
                            agentCashMapper.updateAgentCashOrderByPayment(cash.getPaymentStatus(), cash.getPaymentMsg(), cash.getOrderId());
                        }
                    }
                    return 0;
                }
            }else{
                //只有状态为处理中的才修改(防止手动置修改状态之后再次改变)
                if(cash.getPaymentStatus().equals("P")) {
                    cash.setPaymentStatus("F");
                    cash.setPaymentMsg(response.getSearchResponseBody().getErrorCode() + ":" + response.getSearchResponseBody().getErrorMsg());
                    agentCashMapper.updateAgentCashOrderByPayment(cash.getPaymentStatus(), cash.getPaymentMsg(), cash.getOrderId());
                }
                return 0;
            }
            return 1;
        } catch (Exception e) {
            logger.error("请求超时：", e);
            return -1;
        }
    }

    private String sendQuery(String requestXml,String encoding) throws Exception {
        String url = configUtil.getConfigValue("payment","query_url");            //服务端URL

        //初始化HttpClient
        HttpClient client = new HttpClient();
        PostMethod method = new PostMethod(url);
        SSLContext sslContext = null;
        sslContext = SSLContext.getInstance("TLSv1.2");
        sslContext.init(null, null, null);
        SSLContext.setDefault(sslContext);

        // url的连接等待超时时间设置
        client.getHttpConnectionManager().getParams().setConnectionTimeout(20000);

        // 读取数据超时时间设置
        client.getHttpConnectionManager().getParams().setSoTimeout(30000);
        method.setRequestEntity(new StringRequestEntity(requestXml, "text/html", "utf-8"));
        client.executeMethod(method);

        //打印返回的信息
        InputStream stream = method.getResponseBodyAsStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(stream,encoding));
        StringBuffer buf = new StringBuffer();
        String line;
        while (null != (line = br.readLine())) {
            buf.append(line).append("\n");
        }
        //释放连接
        method.releaseConnection();
        return buf.toString();
    }

    private Pay2bankSearchResult unSealMsg(String msg,String fetureCode, String membercode){
        logger.info("第三方支付结果查询返回密文:" + msg);
        Pay2bankSearchResponse response = CCSUtil_Query.converyToJavaBean(msg, Pay2bankSearchResponse.class);
        SealedData sealedData = new SealedData();
        sealedData.setOriginalData(response.getSearchResponseBody().getSealDataType().getOriginalData()==null?null:PKIUtil.utf8String2ByteWithBase64(response.getSearchResponseBody().getSealDataType().getOriginalData()));
        sealedData.setSignedData(response.getSearchResponseBody().getSealDataType().getSignedData()==null?null:PKIUtil.utf8String2ByteWithBase64(response.getSearchResponseBody().getSealDataType().getSignedData()));
        sealedData.setEncryptedData(response.getSearchResponseBody().getSealDataType().getEncryptedData()==null?null:PKIUtil.utf8String2ByteWithBase64(response.getSearchResponseBody().getSealDataType().getEncryptedData()));
        sealedData.setDigitalEnvelope(response.getSearchResponseBody().getSealDataType().getDigitalEnvelope()==null?null:PKIUtil.utf8String2ByteWithBase64(response.getSearchResponseBody().getSealDataType().getDigitalEnvelope()));
        Mpf mpf = genMpf(fetureCode , membercode);
        UnsealedData unsealedData = null;
        try {
            ICryptoService service = CryptoServiceFactory.createCryptoService();
            unsealedData = service.unseal(mpf, sealedData);
        }catch (CryptoException e){
            logger.error("解密失败：" + e);
        }
        byte[] decryptedData = unsealedData.getDecryptedData();
        String rtnString = "";
        if (null != decryptedData) {
            rtnString = PKIUtil.byte2UTF8String(decryptedData);
        } else {
            rtnString = PKIUtil.byte2UTF8String(sealedData.getOriginalData());
        }
        logger.info("第三方支付结果查询解密后明文：" + rtnString);

        Pay2bankSearchResult respObj = CCSUtil_Query.converyToJavaBean(rtnString, Pay2bankSearchResult.class);

        return respObj;
    }

    private String genQueryDetail(GrantDetailVo detail, String encoding, String fetureCode, String membercode, String version){
        Pay2bankSearchRequestParam orderDto = genOrderDetail(detail);
        String orderXml = CCSUtil_Query.convertToXml(orderDto, encoding);
        logger.info("请求明文报文: " + orderXml);
        //获取原始报文
        String originalStr = orderXml;
        //加签、加密
        Mpf mpf = genMpf(fetureCode , membercode);
        SealedData sealedData = null;
        try {
            ICryptoService service = CryptoServiceFactory.createCryptoService();
            sealedData = service.seal(mpf, originalStr.getBytes());
        } catch (CryptoException e) {
            logger.error("加密失败：", e);
        }
        Pay2bankSearchRequest request = CCSUtil_Query.genRequest(membercode , version);
        byte[] nullbyte = {};
        byte[] byteOri = sealedData.getOriginalData() == null ? nullbyte : sealedData.getOriginalData();
        byte[] byteEnc = sealedData.getEncryptedData() == null ? nullbyte : sealedData.getEncryptedData();
        byte[] byteEnv = sealedData.getDigitalEnvelope() == null ? nullbyte : sealedData.getDigitalEnvelope();
        byte[] byteSig = sealedData.getSignedData() == null ? nullbyte : sealedData.getSignedData();
        request.getSearchRequestBody().getSealDataType().setOriginalData(PKIUtil.byte2UTF8StringWithBase64(byteOri));
        //获取加签报文
        request.getSearchRequestBody().getSealDataType().setSignedData(PKIUtil.byte2UTF8StringWithBase64(byteSig));
//		//获取加密报文
        request.getSearchRequestBody().getSealDataType().setEncryptedData(PKIUtil.byte2UTF8StringWithBase64(byteEnc));
//		//数字信封
        request.getSearchRequestBody().getSealDataType().setDigitalEnvelope(PKIUtil.byte2UTF8StringWithBase64(byteEnv));

        //请求报文
        String requestXml = CCSUtil_Query.convertToXml(request, encoding);
        logger.info("请求加密报文: " + requestXml);
        return requestXml;
    }

    private String genQueryCash(AgentCashOrderVo cash, String encoding, String fetureCode, String membercode, String version){
        Pay2bankSearchRequestParam orderDto = genOrderCash(cash);
        String orderXml = CCSUtil_Query.convertToXml(orderDto, encoding);
        logger.info("请求明文报文: " + orderXml);
        //获取原始报文
        String originalStr = orderXml;
        //加签、加密
        Mpf mpf = genMpf(fetureCode , membercode);
        SealedData sealedData = null;
        try {
            ICryptoService service = CryptoServiceFactory.createCryptoService();
            sealedData = service.seal(mpf, originalStr.getBytes());
        } catch (CryptoException e) {
            logger.error("加密失败：", e);
        }
        Pay2bankSearchRequest request = CCSUtil_Query.genRequest(membercode , version);
        byte[] nullbyte = {};
        byte[] byteOri = sealedData.getOriginalData() == null ? nullbyte : sealedData.getOriginalData();
        byte[] byteEnc = sealedData.getEncryptedData() == null ? nullbyte : sealedData.getEncryptedData();
        byte[] byteEnv = sealedData.getDigitalEnvelope() == null ? nullbyte : sealedData.getDigitalEnvelope();
        byte[] byteSig = sealedData.getSignedData() == null ? nullbyte : sealedData.getSignedData();
        request.getSearchRequestBody().getSealDataType().setOriginalData(PKIUtil.byte2UTF8StringWithBase64(byteOri));
        //获取加签报文
        request.getSearchRequestBody().getSealDataType().setSignedData(PKIUtil.byte2UTF8StringWithBase64(byteSig));
//		//获取加密报文
        request.getSearchRequestBody().getSealDataType().setEncryptedData(PKIUtil.byte2UTF8StringWithBase64(byteEnc));
//		//数字信封
        request.getSearchRequestBody().getSealDataType().setDigitalEnvelope(PKIUtil.byte2UTF8StringWithBase64(byteEnv));

        //请求报文
        String requestXml = CCSUtil_Query.convertToXml(request, encoding);
        logger.info("请求加密报文: " + requestXml);
        return requestXml;
    }

    private static Mpf genMpf(String fetureCode, String membercode) {
        Mpf mpf = new Mpf();
        mpf.setFeatureCode(fetureCode);
        mpf.setMemberCode(membercode);
        return mpf;
    }

    private Pay2bankSearchRequestParam genOrderDetail(GrantDetailVo detail){
        Pay2bankSearchRequestParam order = new Pay2bankSearchRequestParam();
        //页码 必填 正整数
        order.setTargetPage("1");
        //每页条数  必填  1-20  正整数
        order.setPageSize("20");
        //商家订单号
        order.setOrderId(detail.getId());
//        //金额（分）
//        order.setAmount("");
//        //银行名称
//        order.setBankName("");
//        //开户行
//        order.setBranchName("");
//        //收款人姓名
//        order.setCreditName("");
//        //银行卡号
//        order.setBankAcctId("");
        String date = detail.getUpdateTime().substring(0,10);
        //开始时间 必填
        order.setStartDate(date + " 00:00:00"); //2017-11-19 08:12:12
        //结束时间 必填  结束-开始<=7天
        order.setEndDate(date + " 23:59:59"); //2017-11-21 23:59:59
        return order;
    }

    private Pay2bankSearchRequestParam genOrderCash(AgentCashOrderVo cash){
        Pay2bankSearchRequestParam order = new Pay2bankSearchRequestParam();
        //页码 必填 正整数
        order.setTargetPage("1");
        //每页条数  必填  1-20  正整数
        order.setPageSize("20");
        //商家订单号
        order.setOrderId(cash.getOrderId());
//        //金额（分）
//        order.setAmount("");
//        //银行名称
//        order.setBankName("");
//        //开户行
//        order.setBranchName("");
//        //收款人姓名
//        order.setCreditName("");
//        //银行卡号
//        order.setBankAcctId("");
        String date = cash.getApplyTime().toString().substring(0,10);
        //开始时间 必填
        order.setStartDate(date + " 00:00:00"); //2017-11-19 08:12:12
        //结束时间 必填  结束-开始<=7天
        order.setEndDate(date + " 23:59:59"); //2017-11-21 23:59:59
        return order;
    }
}
